package com.alone.wchat.admin.aspect;

import com.alone.wchat.admin.cntext.HostInfo;
import com.alone.wchat.common.utils.ExceptionUtils;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;

/**
 * <p>
 * controller层的状态码aop,对指定的状态码指定不同的动作
 * </p>
 * <ul>
 * <li>对于5xx，需要邮件通知相关人员具体错误信息，并日志记录</li>
 * </ul>
 * 
 * @author weirdor
 *
 */
@Aspect
@Component
//@Profile("production")
public class ControllerStatusCodeAOP {

	private Logger logger = LoggerFactory.getLogger(ControllerStatusCodeAOP.class);

	@Autowired
    HttpServletResponse response;

	@Autowired
    HttpServletRequest request;

	@AfterReturning(pointcut = "execution(public * com.alone.wchat.*..*Controller.*(..))", returning = "returnedValue")
	public void xxx(JoinPoint point, Object returnedValue) {

		if (request != null && response != null) {
			int statusCode = response.getStatus();
			if (statusCode >= 400) {
				String httpMethod = request.getMethod();
				String queryString = request.getQueryString();
				String url;
				try {
					url = ("".equals(queryString) || queryString == null) ? request.getRequestURL().toString()
							: request.getRequestURL() + "?" + URLDecoder.decode(queryString, "utf-8");
				} catch (UnsupportedEncodingException e1) {
					logger.error(ExceptionUtils.getExceptionStack(e1));
					url = StringUtils.isBlank(queryString) ? request.getRequestURL().toString()
							: request.getRequestURL() + "?" + queryString;
				}

				if (statusCode >= 500) {
					logger.error("");
					logger.error("**************************************************************");
					logger.error("************************* 我们出错啦！！！！！！**********************");
					logger.error("**************************************************************");
					Map<String, Object> model = new HashMap<>();

					model.put("method", httpMethod);
					
					Map<String, Object> loggerData = getLoggerData(httpMethod, returnedValue);
					loggerData.put("statusCode", statusCode);
					loggerData.put("url", url);

					// 对客户端，只返回异常简单信息，隐藏异常栈信息
					if (returnedValue instanceof Map) {
						@SuppressWarnings("unchecked")
						Map<String, Object> returnedMap = (Map<String, Object>) returnedValue;
						returnedMap.put("message", "对不起，服务器出错了，我们已收到错误信息并会抓紧修复，还请见谅！");
					}

					logger.error(getJsonStr(loggerData));

					List<String> headers = new ArrayList<>();
					Enumeration<String> headerNames = request.getHeaderNames();
					while (headerNames.hasMoreElements()) {
						String header = headerNames.nextElement();
						String headerValue = request.getHeader(header);
						headers.add(header + " : " + headerValue);
					}

					model.put("data", new Gson().toJson(loggerData.get("data")));
					model.put("hostname", HostInfo.HOSTNAME);
					model.put("publicIp", HostInfo.PUBLICIP);
					model.put("privateIp", HostInfo.PRIVATEIP);
					model.put("url", url);
					model.put("headers", headers);
					model.put("statusCode", statusCode);
					model.put("errorMsg", loggerData.get("errorMessage"));
					model.put("serverDate", new Date());
					System.out.println(model);
					//asyncMethodUtils.sendTemplateDing(model, "emailTemplate/50x.html", "admin", username);
				} else if (statusCode >= 400 && statusCode < 500) {
					if (returnedValue instanceof Map) {
						@SuppressWarnings("unchecked")
						Map<String, Object> returnedMap = (Map<String, Object>) returnedValue;
						Object msgObj = returnedMap.get("message");
						if (msgObj != null && msgObj instanceof Exception) {
							returnedMap.put("message", ((Exception) msgObj).getMessage());
						}
					}
					Map<String, Object> loggerData = getLoggerData(request.getMethod(), returnedValue);
					loggerData.put("statusCode", statusCode);
					loggerData.put("url", url);
					logger.error(getJsonStr(loggerData));
				}
			}
		}
	}

	/**
	 * 日志以json格式展示
	 * @param httpMethod
	 * @param returnedValue
	 * @return
	 */
	private Map<String, Object> getLoggerData(String httpMethod, Object returnedValue) {

		Map<String, Object> loggerData = new HashMap<>();
		loggerData.put("method", httpMethod);

		String errorMsgStr = "";

		if (returnedValue != null) {
			if (returnedValue instanceof Map) {
				@SuppressWarnings("unchecked")
				Map<String, Object> returnedMap = (Map<String, Object>) returnedValue;

				// 提取错误信息字符串
				Object messageObj = returnedMap.get("message");
				if (messageObj instanceof Exception) {
					Exception exception = (Exception) messageObj;
					ByteArrayOutputStream os = new ByteArrayOutputStream();
					PrintStream ps = new PrintStream(os);
					exception.printStackTrace(ps);
					errorMsgStr = new String(os.toByteArray());
					ps.close();

					returnedMap.put("message", exception.getMessage());
				} else {
					errorMsgStr = messageObj.toString();
				}

				// 如果是put或者post方法，还需加上请求数据，存放在returnedValue中的data中
				if ("put".equalsIgnoreCase(httpMethod) || "post".equalsIgnoreCase(httpMethod)) {
					loggerData.put("data", returnedMap.get("data"));
				} else {
					loggerData.put("data", "-");
				}
			} else {
				errorMsgStr = returnedValue.toString();
			}
		}

		loggerData.put("errorMessage", errorMsgStr);

		return loggerData;
	}

	private String getJsonStr(Map<String, Object> data) {
		return new Gson().toJson(data);
	}
}
